package com.loong.tool.secret.security.digest;

import java.security.KeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import com.loong.tool.secret.base.Base64;
import com.loong.tool.secret.base.Hex;
import com.loong.tool.secret.base.UTF8;
import com.loong.tool.secret.exception.InvalidCodeException;
import com.loong.tool.secret.exception.InvalidKeyException;
import com.loong.tool.secret.exception.SecretVariableException;

/**
 * Mac信息摘要处理类
 * 
 * @author 张成轩
 */
public class MacDigest {

	/**
	 * 摘要算法
	 */
	public enum Algorithm {

		/** HmacMD5算法 */
		HMAC_MD5("HmacMD5"),
		/** HmacSHA1算法 */
		HMAC_SHA1("HmacSHA1"),
		/** HmacSHA256算法 */
		HMAC_SHA256("HmacSHA256"),
		/** HmacSHA384算法 */
		HMAC_SHA384("HmacSHA384"),
		/** HmacSHA512算法 */
		HMAC_SHA512("HmacSHA512");

		private String value;

		private Algorithm(String value) {

			this.value = value;
		}
	}

	/** 默认加密类型 */
	private static final Algorithm DEFAULT = Algorithm.HMAC_SHA256;

	/**
	 * 生成密钥
	 * 
	 * @return 密钥
	 */
	public static String getKey() {

		return getKey(DEFAULT);
	}

	/**
	 * 生成密钥
	 * 
	 * @param algorithm 算法
	 * @return 密钥
	 */
	public static String getKey(Algorithm algorithm) {

		// 初始化密钥生成对象
		KeyGenerator kg;
		try {
			kg = KeyGenerator.getInstance(algorithm.value);
		} catch (NoSuchAlgorithmException e) {
			throw new SecretVariableException("MacDigest variable init error: " + algorithm.name());
		}
		// 生成密钥
		return Base64.encode(kg.generateKey().getEncoded());
	}

	/**
	 * 信息摘要处理
	 * 
	 * @param str 信息摘要
	 * @param key 密钥
	 * @return 摘要后字符串
	 * @throws InvalidKeyException 无效密钥异常
	 */
	public static String digest(String str, String key) throws InvalidKeyException {

		return digest(str, key, DEFAULT);
	}

	/**
	 * 信息摘要处理
	 * 
	 * @param str 信息摘要
	 * @param key 密钥
	 * @param algorithm 算法
	 * @return 摘要后字符串
	 * @throws InvalidKeyException 无效密钥异常
	 */
	public static String digest(String str, String key, Algorithm algorithm) throws InvalidKeyException {

		Mac mac = null;
		try {
			// 初始化密钥对象
			SecretKey secretKey = new SecretKeySpec(Base64.decode(key), algorithm.value);
			// 初始化摘要对象
			mac = Mac.getInstance(secretKey.getAlgorithm());
			mac.init(secretKey);
		} catch (NoSuchAlgorithmException e) {
			throw new SecretVariableException("MacDigest variable init error: " + algorithm.name());
		} catch (KeyException | InvalidCodeException e) {
			throw new InvalidKeyException(e);
		}
		// 摘要处理
		return Hex.encode(mac.doFinal(UTF8.getBytes(str)));
	}
}
